﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using SpectationClient;
using SpectationClient.Stuff;
using SpectationClient.SQLCommandBuilder;

using Npgsql;
using SpectationClient.DataBaseDescription;
using SpectationClient.Async;

namespace SpectationClient.GUI {
    public partial class SubInsertGFZPhotos : Form {
        UC_ParseNumbers SPECIDS_PARSE_UC;
        ErrorList EL;
        DBManager DBM;

        private bool SQL_INIT_CORRECT = true;
        private Dictionary<TableInfo, Object> initObject = new Dictionary<TableInfo, Object>();
        private int sql_init_tables = 0;

        /// <summary>
        /// Background Worker to initialize objects.
        /// </summary>
        private AGetDatabaseObject AGDO;
       
        BackgroundWorker BGW_INSERT;

        //PostGIS_Npgsql_CommandBuilder CMB = new PostGIS_Npgsql_CommandBuilder();
        OpenFileDialog OFD = new OpenFileDialog();

        public SubInsertGFZPhotos(ref DBManager dbm) {
            InitializeComponent();

            this.Icon = Resources.Icon;
            DBM = dbm;
            EL = new ErrorList();
            AGDO = new AGetDatabaseObject();
            AGDO.GetDataTableCompleted +=new GetDataTableCompletedEventHandler(AGDO_GetDataTableCompleted);

            BGW_INSERT = new BackgroundWorker();
            BGW_INSERT.DoWork += new DoWorkEventHandler(BGW_INSERT_DoWork);
            BGW_INSERT.WorkerReportsProgress = true;
            BGW_INSERT.WorkerSupportsCancellation = true;
            BGW_INSERT.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BGW_INSERT_RunWorkerCompleted);
            
            EL.ErrorListIsEmpty += new EventHandler(checkCommand);
            SPECIDS_PARSE_UC = new UC_ParseNumbers();
            SPECIDS_PARSE_UC.LabelsChanged += new EventHandler(checkCommand);
            SPECIDs_PANEL.Controls.Add(SPECIDS_PARSE_UC);

            Photos_DGV.CellValueChanged +=new DataGridViewCellEventHandler(Photos_DGV_SelectionChanged);

            ColumnInfo ci = DBM.getColumnInfo("CORE", "PHOTOS", "purpose");
            FormHelper.initComboBoxItems(ColType, ci.possibleValues, false);
            DataBaseInfo DBI = DBM.getDataBaseInfo();
            initObject.Add(DBI["CORE"]["OPERATORS"], Photo_Operator);
            initObject.Add(DBI["CORE"]["CAMERAS"], Photo_Camera);
            this.ts_progressbar.Value = 0;
            this.ts_progressbar.Maximum = sql_init_tables += initObject.Count;
            foreach(TableInfo ti in this.initObject.Keys) {
                NpgsqlCommand cmdSelect = CommandBuilder.getSELECT(ti);
                cmdSelect.Connection = this.DBM.Connection;
                AGDO.GetDataTableAsync(cmdSelect, ti);
            }

           
        }

        

        void AGDO_GetDataTableCompleted(object sender, GetDataTableCompletedEventArgs e) {
            TableInfo ti = (TableInfo)e.UserState;

            if(e.Cancelled) {

            } else if(e.Error != null) {
                this.SQL_INIT_CORRECT = false;
                this.RTB_SQL.Text += TextHelper.Exception2String(e.Error);
            } else {
                Object[] objects = (this.initObject[ti] is Object[]) ? (Object[])this.initObject[ti] : new Object[] { this.initObject[ti] };

                foreach(Object o in objects) {

                    ComboBox cb = o as ComboBox;
                    if(cb != null) {
                        FormHelper.initComboBoxItems(cb, e.DataTable, ti, true);
                    }

                    DataGridViewComboBoxColumn cbc = o as DataGridViewComboBoxColumn;
                    if(cbc != null) {
                        FormHelper.initComboBoxItems(cbc, e.DataTable, ti, true);
                    }

                    DataTable dtToInitialize = o as DataTable;
                    if(dtToInitialize != null) {
                        dtToInitialize = e.DataTable;
                    }
                }
                this.initObject.Remove(ti);
            }


            this.ts_progressbar.Value = sql_init_tables - initObject.Count;
            if(this.initObject.Count == 0) {
                if(this.SQL_INIT_CORRECT) {
                    this.bt_INSERT_PHOTOS.Enabled = true;
                    this.RTB_SQL.Text = "Initialisierung abgeschlossen";
                 
                } else {
                    this.RTB_SQL.Text = "Initialisierung fehlgeschlagen";
                }
            } 
        }

       
        void BGW_INSERT_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {

            if (e.Cancelled) {
                
                MessageBox.Show("Übertragung abgebrochen");

            } else if (e.Error != null) {
                
                FormHelper.ShowErrorBox(e.Error);

            } else {
                Object o = e.Result;
                MessageBox.Show("Fotos erfolgreich eingefügt und mit den Spektren verknüpft.");
                Photos_DGV.Rows.Clear();
                SPECIDS_PARSE_UC.clear();
                uC_ImageViewer1.showImage(null);
            }

        }

        void BGW_INSERT_ProgressChanged(object sender, ProgressChangedEventArgs e) {
            ts_progressbar.Value = e.ProgressPercentage;
            ts_statuslabel.Text = e.UserState.ToString();
        }

        void BGW_INSERT_DoWork(object sender, DoWorkEventArgs e) {


            BGWInfo_StorePhotos bgi = (BGWInfo_StorePhotos)e.Argument;
            BackgroundWorker meself = (BackgroundWorker)sender;
            NpgsqlConnection con = bgi.insertPhotosCommand.Connection;
            con.Open();
            NpgsqlTransaction trans = con.BeginTransaction(IsolationLevel.ReadCommitted);

            bool done = true;
            try {
                //Insert new Photos
                meself.ReportProgress(14, "Add to CORE.PHOTOS...");
                DataTable newPhotoIDs = CommandHelper.getReturningTable(bgi.insertPhotosCommand, con, trans);
                Type photoidtype = newPhotoIDs.Rows[0][0].GetType();

                if(meself.CancellationPending) return;

                if (newPhotoIDs != null) {
                    //Add bridge-tableName informations 
                    meself.ReportProgress(50, "Add to CORE.BT_PHOTOS...");
                
                    InsertValueCollection rvcPhotos = new InsertValueCollection(ref bgi.tiBT_Photos);
                
                    //N:M Photos
                    foreach (Int64 idSpectrum in bgi.spectraIDs) {
                        foreach (DataRow row in newPhotoIDs.Rows) {
                            
                            InsertValues iv = new InsertValues(ref bgi.tiBT_Photos);
                            iv.Add("id_spectrum",idSpectrum);
                            iv.Add("id_photo", row["id"]);
                            rvcPhotos.Add(iv);
                            
                        }
                        if(meself.CancellationPending) return;

                    }
                    if(rvcPhotos.Count > 0){
                        NpgsqlCommand cmd = rvcPhotos.getInsertCmd();
                        cmd.Connection = con;
                        cmd.Transaction = trans;
                        cmd.ExecuteNonQuery();
                       
                    }
                    if(meself.CancellationPending) return;

                }
              
                e.Result = bgi;
                if(meself.CancellationPending) return;

             
            } catch (Exception ex) {
                
                done = false;
                throw ex;

            } finally {
                
                if(done) {
                    trans.Commit();
                    meself.ReportProgress(100, "");
                } else {
                    trans.Rollback();
                }


                con.Close();
            }
        }


        void checkCommand(object sender, EventArgs e) {
            checkCommand();
            
        }

        void checkCommand(object sender, DataGridViewCellEventArgs e) {
            checkCommand();
        }

        private bool checkCommand() {
            if(EL == null) return false;
            EL.removeAllErrors();
            if (SPECIDS_PARSE_UC.Count == 0) {
                //errortext += "Bitte die spectraIDs existierender Spektren angeben\n";
                EL.addError(SPECIDs_PANEL, "Keine Spektren IDs angeben");
            }
            if(Photos_DGV.RowCount == 0) {
                EL.addError(Photos_DGV, "Keine Fotos angeben");
                //errortext += "Bitte die einzufügenden Fotos angeben\n";
            } else { 
                int iPhoto = ColPhotos.Index;
                int iType = ColType.Index;

                foreach(DataGridViewRow r in Photos_DGV.Rows) {
                    if(r.Cells[iPhoto].Value != null && 
                       r.Cells[iType].Value == null) EL.addError(r.Cells[iType], "Art des Fotos auswählen");
                
                }
                
            }
            if (EL.Count > 0) {
                bt_INSERT_PHOTOS.Enabled = false;
                RTB_SQL.Text = "Bitte Angaben vervollständigen";
                return false;
            } else {
                RTB_SQL.Text =  CommandBuilder.CommandToString(getCMD_PHOTOS());
                bt_INSERT_PHOTOS.Enabled = true;
            }
            return true;
        }


        private NpgsqlCommand getCMD_PHOTOS() {
            //Weather-Photos
            TableInfo ti = DBM.getTableInfo("CORE", "PHOTOS");
            ColumnInfoImageFile ifc = (ColumnInfoImageFile)ti["file"];
            InsertValueCollection ivc = new InsertValueCollection(ref ti);

            Int32 iPhoto = ColPhotos.Index;
            Int32 iPurpose = ColType.Index;
            Int32 iNotes = ColNotes.Index;

            foreach (DataGridViewRow r in Photos_DGV.Rows) {
                DGVExtensions.DataGridViewPhotoCell cell = (DGVExtensions.DataGridViewPhotoCell) r.Cells[iPhoto];
                if (!r.IsNewRow && cell.Value is FileInfo) {
                    InsertValues iv = new InsertValues(ref ti);
                    FileInfo fileInfo = cell.Value as FileInfo;
                        
                    byte[] ba = File.ReadAllBytes(fileInfo.FullName);
                    System.Drawing.Imaging.ImageFormat format = DataHelper.getImageFormat(ba);
                    Image preview = DataHelper.makePreview(ba, 300, 300);
                    iv.Add("filepreview", DataHelper.ImageToByteArray(preview, format));
                    iv.AddFile(fileInfo, "file", "filename", null, "filetype");
                        
                    iv.Add("purpose", r.Cells[iPurpose]);
                    iv.Add("id_camera", Photo_Camera);
                    iv.Add("id_operator", Photo_Operator);

                    
                    DateTime dt1 = Time_dateTimePicker.Value;
                    DateTime dt2 = Time_TimeStart.Value;
                    iv.Add("datetime", new DateTime(dt1.Year, dt1.Month, dt1.Day, dt2.Hour, dt2.Minute, dt2.Second, dt2.Millisecond, DateTimeKind.Local));
                    iv.Add("notes", r.Cells[iNotes].Value);
                    ivc.Add(iv);
                }
            }

            return ivc.getInsertCmd(true);
        }
     
       
        private void Photos_DGV_RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e) {
            EL.checkforDisposedElements();
            
            checkCommand();
        }

        private void Photos_btAddPhotos_Click(object sender, EventArgs e) {
            List<FileInfo> files = FormHelper.getPhotoFileInfos(true, "Bitte Fotos auswählen");


            int iPhoto = ColPhotos.Index;

            List<FileInfo> existing = (from DataGridViewRow row in Photos_DGV.Rows
                                       where row.Cells[iPhoto].Value is FileInfo
                                       select (FileInfo)row.Cells[iPhoto].Value).ToList();

            files = files.Except(existing).ToList();

            foreach(FileInfo newFile in files) {
                int iNew = Photos_DGV.Rows.Add();
                Photos_DGV.Rows[iNew].Cells[iPhoto].Value = newFile;
                Photos_DGV.Rows[iNew].Cells[iPhoto].ToolTipText = newFile.FullName;
                if(Photos_DGV.RowCount == 1) Photos_DGV_SelectionChanged(null, null);
            }

        }

        private void Photos_DGV_SelectionChanged(object sender, EventArgs e) {
            btRemovePhoto.Enabled = Photos_DGV.SelectedRows.Count > 0;
            List<DataGridViewRow> dr = FormHelper.getSelectedRows(this.Photos_DGV);
            int iPhoto = ColPhotos.Index;
            foreach(DataGridViewRow row in dr) {
                DGVExtensions.DataGridViewPhotoCell CELL = row.Cells[iPhoto] as DGVExtensions.DataGridViewPhotoCell;
                if(CELL != null && CELL.Value != null) {
                    uC_ImageViewer1.showImage(CELL.getImage());
                }

            }
        }

     


        private void bt_INSERT_PHOTOS_Click(object sender, EventArgs e) {
            try {

                NpgsqlCommand insertPhotosCommand = getCMD_PHOTOS();
                insertPhotosCommand.Connection = this.DBM.Connection;
                BGWInfo_StorePhotos bgi = new BGWInfo_StorePhotos(insertPhotosCommand, SPECIDS_PARSE_UC.Numbers, 
                                                                   this.DBM.getDataBaseInfo()["CORE"]["BT_PHOTOS"]);
                BGW_INSERT.RunWorkerAsync(bgi);

            } catch (Exception ex) {
                MessageBox.Show(ex.Message);
            }
        }

        private void btRemovePhoto_Click(object sender, EventArgs e) {
            FormHelper.removeSelectedRows(Photos_DGV);
        }

        /// <summary>
        /// Struct to store values required to insert photos in a background process.
        /// </summary>
        private class BGWInfo_StorePhotos {
            public List<Int64> spectraIDs;
            public NpgsqlCommand insertPhotosCommand;
            public TableInfo tiBT_Photos;
            public BGWInfo_StorePhotos(NpgsqlCommand insertPhotosCommand, List<Int64> spectraIDs, TableInfo tiBT_Photos) {
                this.insertPhotosCommand = insertPhotosCommand;
                this.spectraIDs = spectraIDs;
                this.tiBT_Photos = tiBT_Photos;
            }
        }
    }
    
    
}
